package com.whz.generic.utils;

import lombok.experimental.UtilityClass;
import org.springframework.util.StringUtils;
import org.springframework.web.util.UriComponentsBuilder;

import java.net.MalformedURLException;
import java.net.URI;
import java.net.URL;
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
import java.util.regex.Pattern;

/**
 * http url utility
 *
 * @author whz
 */
@UtilityClass
public class UrlUtils {

    private static final Set<String> PUBLIC_PREFIX = new HashSet<>(
            Arrays.asList(
                    "com|org|net|gov|edu|co|tv|mobi|info|asia|xxx|onion|cn|com.cn|edu.cn|gov.cn|net.cn|org.cn|jp|kr|tw|com.hk|hk|com.hk|org.hk|se|com.se|org.se"
                            .split("\\|")));

    private static final Pattern IP_PATTERN = Pattern.compile("(\\d{1,3}\\.){3}(\\d{1,3})");
    /**
     * http 分隔符 /
     */
    public static final String SEPARATOR = "/";
    public static final String SPOT = ".";
    private static final Pattern COMPILE = Pattern.compile("\\+", Pattern.LITERAL);

    /**
     * 获取url的顶级域名
     *
     * @param url 任意URL
     */
    public static String getDomainName(URL url) {
        String host = url.getHost();
        if (host.endsWith(SPOT)) {
            host = host.substring(0, host.length() - 1);
        }
        if (IP_PATTERN.matcher(host).matches()) {
            return host;
        }

        int index = 0;
        String candidate = host;
        while (index >= 0) {
            index = candidate.indexOf('.');
            String subCandidate = candidate.substring(index + 1);
            if (PUBLIC_PREFIX.contains(subCandidate)) {
                return candidate;
            }
            candidate = subCandidate;
        }
        return candidate;
    }

    /**
     * 获取url的顶级域名
     *
     * @param url 任意URL
     * @return String
     */
    public static String getDomainName(String url) {
        try {
            final URL urlObj = new URL(url);
            return getDomainName(urlObj);
        } catch (MalformedURLException e) {
            return url;
        }
    }

    /**
     * 判断两个url顶级域名是否相等
     *
     * @param url1 任意URL
     * @param url2 任意URL
     */
    public static boolean isSameDomainName(URL url1, URL url2) {
        return getDomainName(url1).equalsIgnoreCase(getDomainName(url2));
    }

    /**
     * 判断两个url顶级域名是否相等
     *
     * @param url1 任意URL
     * @param url2 任意URL
     */
    public static boolean isSameDomainName(String url1, String url2) {
        try {
            return isSameDomainName(new URL(url1), new URL(url2));
        } catch (MalformedURLException e) {
            return false;
        }
    }

    /**
     * URI更新协议
     */
    public static URI upgradeConnection(URI uri, String scheme) {
        UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUri(uri)
                                                                        .scheme(scheme);
        queryConvert(uri, uriComponentsBuilder);
        return uriComponentsBuilder.build(true).toUri();
    }

    /**
     * URI更新path
     */
    public static URI upgradePath(URI uri, String path) {
        UriComponentsBuilder uriComponentsBuilder = UriComponentsBuilder.fromUri(uri)
                                                                        .path(path);
        queryConvert(uri, uriComponentsBuilder);
        return uriComponentsBuilder.build(true).toUri();
    }

    private static void queryConvert(URI uri, UriComponentsBuilder uriComponentsBuilder) {
        if (uri.getRawQuery() != null) {
            uriComponentsBuilder.replaceQuery(COMPILE.matcher(uri.getRawQuery()).replaceAll("%20"));
        }
    }

    public static String deleteStartChar(final String text, final String startChar) {
        String input = text;
        if (StringUtils.hasText(input) && StringUtils.hasText(startChar)) {
            while (input.startsWith(startChar)) {
                input = input.substring(1);
            }
            return input;
        }
        return text;
    }

    public static String deleteEndChar(final String text, final String endChar) {
        String input = text;
        if (StringUtils.hasText(input) && StringUtils.hasText(endChar)) {
            while (input.endsWith(endChar)) {
                input = input.substring(0, input.length() - 1);
            }
            return input;
        }
        return text;
    }

    public static String deleteStartFileSeparator(final String path) {
        return deleteStartChar(path, SEPARATOR);
    }

    public static String deleteEndFileSeparator(final String path) {
        return deleteEndChar(path, SEPARATOR);
    }
}